/*
* MIT License
*
* Copyright (c) 2017 wen.gu <454727014@qq.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

/***************************************************************************
* Name: tiny_oopc.h
*
* Purpose: Object Oriented Programming with c language
*
* Developer:
*   wen.gu , 2018-08-21
*
* TODO:
*
***************************************************************************/

#ifndef __TINYE_OOPC_H__
#define __TINYE_OOPC_H__

#include "general_type.h"

#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************
*
* macro define
*
***************************************************************************/
#if defined(HAVE_STD_OFFSETOF)
#define USE_STD_OFFSETOF
#else
#define USE_USER_DEF_OFFSETOF
#endif

//////////////////////////////////////////////////////////////////////////

#define OOPC_MALLOC(size, typeName, fileName, lineNum) malloc(size)
#define OOPC_FREE  free
#define OOPC_DELETE(cthis, name) printf("delete obj" #cthis ", class(%s)\n",name); OOPC_FREE(cthis)
#define OOPC_CTOR_PARAM  const char* file, int line

#define OOPC_TRUE  1
#define OOPC_FALSE 0
//////////////////////////////////////////////////////////////////////////

#if defined(USE_STD_OFFSETOF)
#include <stddef.h>
#define OOPC_OFFSETOF offsetof
#elif defined(USE_USER_DEF_OFFSETOF)
#define OOPC_OFFSETOF(s,m) (size_t)&(((s*)0)->m)
#endif



/***************************************************************************
*
* data struct declaration
*
***************************************************************************/
typedef int(*class_dtor_f)(void* classhd);

typedef struct oopc_base_s
{
    unsigned int isDeleted;
    const char* name;
    void* cthis;
    class_dtor_f dtor;
    struct oopc_base_s* parent;
    struct oopc_base_s* child;
}oopc_base_t;
/***************************************************************************
*
* API declaration
*
***************************************************************************/

//////////////////////////////////////////////////////////////////////////
/**
* interface declaration,this just define function,cann't define data member
*/
#define INTERFACE(type)             \
typedef struct type type;           \
void type##_ctor(type* t);          \
int type##_dtor(void* t);           \
struct type{


#define END_INTERFACE };

/**
* abstract class declaration,this class
*/
#define ABS_CLASS(type)             \
typedef struct type type;           \
void type##_ctor(type* t);          \
int type##_dtor(void* t);           \
struct type{


#define END_ABS_CLASS oopc_base_t __obj;};

/**
* class declaration,this class
*/
#define CLASS(type)                 \
typedef struct type type;           \
void type##_ctor(void* t);          \
int type##_dtor(void* t);           \
struct type{


#define END_CLASS oopc_base_t __obj;};

//////////////////////////////////////////////////////////////////////////

/*data/interface type: private, public */
#define PROTECTED_DATA(classType)   struct classType##ProtectData{
#define END_PROTECTED_DATA     }protectData;

//////////////////////////////////////////////////////////////////////////

/** constructor function define*/
#define CTOR(type)                          \
void type##_ctor(void* t) {type* cthis = (type*)t; cthis->__obj.cthis = cthis;


#define END_CTOR }

/**
*destructor function define
*note: if define destructor, then must call DTOR_FUNC_SETTING to set destructor function
*see also DTOR_FUNC_SETTING
*/
#define DTOR(type)      \
    int type##_dtor(void* t){type* cthis = (type*)t;

#define END_DTOR return OOPC_TRUE;}

/** abstract class constructor function define */
#define ABS_CTOR(type)              \
    void type##_ctor(type* cthis) {cthis->__obj.cthis = cthis;

#define END_ABS_CTOR }

#define ABS_DTOR     DTOR
#define END_ABS_DTOR END_DTOR

//////////////////////////////////////////////////////////////////////////

#define FUNCTION_SETTING(f1, f2)    cthis->f1 = f2

#define OVERRIDE_FUNC_SETTING(father, f1, f2) cthis->father.f1 = f2

#define IMPLEMENT_FUNC_SETTING OVERRIDE_FUNC_SETTING

/**
*if defined destructor, then must call this macro to set destructor function
*see also DTOR
*/
#define DTOR_FUNC_SETTING(type)     cthis->__obj.dtor = type##_dtor

#define ABS_DTOR_FUNC_SETTING  DTOR_FUNC_SETTING

#define PROTECTED_FUNC_SETTING(f1, f2) OVERRIDE_FUNC_SETTING(protectData, f1, f2)
//////////////////////////////////////////////////////////////////////////

#define IMPLEMENTS(type)    struct type type

#define EXTENDS(type)       struct type type

//////////////////////////////////////////////////////////////////////////
#define SUPER_PTR(cthis, father) ((father*)(&(cthis->father)))

#define SUPER_PTR_2(cthis, father, grandfather) \
    SUPER_PTR(SUPER_PTR(cthis, father), grandfather)

#define SUPER_PTR_3(cthis, father, grandfather, greatgrandfather) \
    SUPER_PTR(SUPER_PTR_2(cthis, father, grandfather), greatgrandfather)

/**!!!!!!!note PROTECTE just inner use or inherit class!!!!!!!!!!!!!*/
#ifdef __cplusplus /*c++ have scope limit */
#define PROTECTED_DATA_TYPE(classType)   struct classType::classType##ProtectData
#else
#define PROTECTED_DATA_TYPE(classType)   struct classType##ProtectData
#endif
#define PROTECTED_PTR(cthis, classType) ((PROTECTED_DATA_TYPE(classType)*)(&((cthis)->protectData)))
#define SUPER_PROTECTED_PTR(cthis, father) PROTECTED_PTR(SUPER_PTR(cthis, father), father)

//////////////////////////////////////////////////////////////////////////

#define SUPER_CTOR(father) \
    father##_ctor(SUPER_PTR(cthis, father)); \
    (cthis->father).__obj.child = &(cthis->__obj); \
    cthis->__obj.parent = &((cthis->father).__obj)

//////////////////////////////////////////////////////////////////////////

#define SUB_PTR(selfptr, self, child) \
    ((child*)((char*)selfptr - OOPC_OFFSETOF(child, self)))

#define SUB_PTR_2(selfptr, self, child, grandchild) \
    SUB_PTR(SUB_PTR(selfptr, self, child), child, grandchild)

#define SUB_PTR_3(selfptr, self, child, grandchild, greatgrandchild) \
    SUB_PTR(SUB_PTR_2(selfptr, self, child, grandchild), grandchild, greatgrandchild)

#define INHERIT_FROM(father, cthis, field)  cthis->father.field

//////////////////////////////////////////////////////////////////////////
    /** create a class instance */
#define CLASS_NEW(type)  \
    (type*)oopcCreate(__FILE__, __LINE__, #type, sizeof(type), type##_ctor)  

    /** release a class instance */
#define CLASS_DELETE(classPtr)   \
    oopcDestroy(__FILE__, __LINE__, classPtr, sizeof(*(classPtr)))


G_API void* oopcCreate(const char* file, int line, const char* className, unsigned int size, void(*ctor)(void* t));
G_API void oopcDestroy(const char* file, int line, void* classPtr, unsigned int size);

#ifdef __cplusplus
}
#endif
#endif //end of __TINYE_OOPC_H__
